package com.bzkj.basicinfo.service.impl.ncc;

import cn.hutool.core.collection.CollectionUtil;
import com.bzkj.basicinfo.domain.basic.BasicStoArea;
import com.bzkj.basicinfo.domain.basic.vo.StoUnitVo;
import com.bzkj.basicinfo.domain.ncc.BasicStoShelf;
import com.bzkj.basicinfo.domain.ncc.StoArea;
import com.bzkj.basicinfo.domain.ncc.StoUnit;
import com.bzkj.basicinfo.domain.ncc.Warehouse;
import com.bzkj.basicinfo.domain.wms.vo.*;
import com.bzkj.basicinfo.mapper.BasicStoAreaMapper;
import com.bzkj.basicinfo.mapper.BasicStoShelfMapper;
import com.bzkj.basicinfo.mapper.StoUnitMapper;
import com.bzkj.basicinfo.mapper.WarehouseMapper;
import com.bzkj.basicinfo.service.ncc.StoAreaService;
import com.bzkj.basicinfo.service.ncc.StoUnitService;
import com.bzkj.basicinfo.utils.GenerateQRCodeUtils;
import com.bzkj.common.core.domain.AjaxResult;
import com.bzkj.common.core.domain.R;
import com.bzkj.common.core.domain.entity.SysUser;
import com.bzkj.common.core.domain.model.LoginUser;
import com.bzkj.common.core.page.TableDataInfo;
import com.bzkj.common.exception.ServiceException;
import com.bzkj.common.utils.DataProcessCommonUtils;
import com.bzkj.common.utils.DateUtils;
import com.bzkj.common.utils.SecurityUtils;
import com.bzkj.common.utils.StringUtils;
import com.bzkj.common.utils.poi.ExcelPDFUtil;
import com.bzkj.common.utils.poi.ExcelUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

import static com.bzkj.common.utils.SecurityUtils.getUsername;


/**
 * @Author: Admin
 * @Description: 货位服务实现类，提供货位的业务逻辑处理
 */
@Service
@Slf4j
public class StoUnitServiceImpl implements StoUnitService
{

    @Autowired
    private StoUnitMapper stoUnitMapper; // 注入货位数据访问层
    @Autowired
    private BasicStoShelfMapper basicStoShelfMapper;

    @Autowired
    private WarehouseMapper warehouseMapper;

    @Autowired
    private BasicStoAreaMapper basicStoAreaMapper;
    @Autowired
    private GenerateQRCodeUtils generateQRCodeUtils;
    @Autowired
    private StoAreaService stoAreaService;

    @Transactional
    @Override
    public AjaxResult addStoUnit(StoUnit stoUnit)
    {
        if(StringUtils.isBlank(stoUnit.getStoAreaId())){
            return AjaxResult.error("货区不能为空，请选择货区");
        }
        String def1 = stoUnit.getDef1();
        Integer def2 = 1;
        String diDui = "";

        int i1 = 1;
        String stoId = stoUnit.getStoId();
        //货位code数据组装正常货位
        List<String> sto_unit_code = new ArrayList<>();
        if (NumberUtils.isCreatable(stoUnit.getDef2())) {
            def2 = Integer.valueOf(stoUnit.getDef2());
            sto_unit_code = generateCodes(def1, def2, stoUnit.getLayerCount(), stoUnit.getPositionsPerLayer(), i1, stoId, stoUnit.getStoAreaId(),stoUnit.getFlag());
        } else {
            //货位code数据组装地堆货位
            diDui = stoUnit.getDef2();
            sto_unit_code = generateDiDuiCodes(def1, def2, diDui, stoUnit.getLayerCount(), stoUnit.getPositionsPerLayer(), i1, stoId, stoUnit.getSonCode(), stoUnit.getStoAreaId(), stoUnit.getIsSonShow());
        }
        //        准备数据
        Date date = new Date();
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser user = loginUser.getUser();
        String userName = user.getUserName();
        Long userId = user.getUserId();
        Long deptId = user.getDeptId();
        //获取货位表中的所有编码并和新生成的编码取交集
        List<StoUnit> stoUnits = stoUnitMapper.selectAllStoUnitCode(stoId,stoUnit.getStoAreaId());
        List<String> collect = stoUnits.stream().map(StoUnit::getStoUnitCode).collect(Collectors.toList());
        List<String> collect1 = collect.stream().filter(sto_unit_code::contains).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(collect1)) {
            return AjaxResult.error("编码不能重复");
        }
        for(int i = 0; i < sto_unit_code.size(); i++) {
            stoUnit.setCreatetime(date);
            stoUnit.setCreator(userName);
            stoUnit.setUserId(userId);
            stoUnit.setDeptId(deptId);
            stoUnit.setDef1("");
            stoUnit.setDef2("");
            stoUnit.setDef3("");
            stoUnit.setDef4("");
            stoUnit.setGubflag(def1);
            stoUnit.setStoUnitCode(sto_unit_code.get(i));
            stoUnitMapper.insertStoUnit(stoUnit);
        }
        return AjaxResult.success();
    }

    /**
     *
     * @param prefix 货架类型
     * @param totalCount 货架数量
     * @param levels 货架层数
     * @param itemsPerLevel 层货位数
     * @param startNumber 货位区开始编号
     * @param stoId 仓库id
     * @desc  非地堆货位生成规则
     */
    public List<String> generateCodes(String prefix, int totalCount, int levels, int itemsPerLevel, int startNumber,
                                      String stoId, String stoAreaId,String flag) {
        // 创建一个 List 用来存储所有生成的编码
        List<String> codes = new ArrayList<>();
        //根据 ID 查询仓库信息
        Warehouse warehouse = warehouseMapper.selectWarehouseById(stoId);
        if(Objects.isNull(warehouse)){
            return new ArrayList<>();
        }
        BasicStoArea stoArea = basicStoAreaMapper.selectBasicStoAreaById(stoAreaId);
        if(Objects.isNull(stoArea)){
            return new ArrayList<>();
        }
        //判断是按照货架数量哈斯货架号生成
        if(flag.equals("0")){
            //查询货位表获取最大的排序作为货位区开始编号
            String stoCode = warehouse.getStoCode() + "-" +stoArea.getStoAreaCode()+"-"+prefix;
            //模糊查询仓库下的这一类货位数据
            List<StoUnit> stoUnits = stoUnitMapper.selectStoCode(stoCode, stoId, stoAreaId);
            List<String> codeList = new ArrayList<>();
            if (CollectionUtil.isNotEmpty(stoUnits)) {
                String finalStoCode = stoCode;
                stoUnits.forEach(i -> {
                    String replaceAll = i.getStoUnitCode().replaceAll(finalStoCode, "");
                    codeList.add(replaceAll.substring(0, 2));
                });
            }
            int starNum = 1;
            if(CollectionUtil.isNotEmpty(codeList)){
                //去重排序
                List<String> collect = codeList.stream().distinct().collect(Collectors.toList());
                Collections.reverse(collect);
                //获取编码的开始位
                String value = collect.get(0);
                //根据value获取id
                starNum = warehouseMapper.selectDataDicListByUValue(value);
            }
            //查询库区位数据字典
            List<String> list = warehouseMapper.selectDataDicList(starNum+1, (totalCount + starNum));
            // 循环生成每个编码，从 startNumber 开始
            for (int i = 0; i < totalCount; i++) {
                String format = list.get(i);
                String codePrefix = String.format("%s-%s-%s%s", warehouse.getStoCode(), stoArea.getStoAreaCode(),prefix,format);
                for (int j = 1; j <= levels; j++) {
                    for (int k = 1; k <= itemsPerLevel; k++) {
                        String code = String.format("%s-%02d-%02d", codePrefix, j, k);
                        codes.add(code);
                    }
                }
            }
            basicStoShelfMapper.updateBasicStoShelfByDef1((totalCount + startNumber) + "", prefix);
        }else{
            String codePrefix = String.format("%s-%s-%s%s", warehouse.getStoCode(), stoArea.getStoAreaCode(),prefix,totalCount);
            for (int j = 1; j <= levels; j++) {
                for (int k = 1; k <= itemsPerLevel; k++) {
                    String code = String.format("%s-%02d-%02d", codePrefix, j, k);
                    codes.add(code);
                }
            }
        }
        return codes;
    }
    /**
     *
     * @param prefix 货架类型
     * @param totalCount 货架数量
     * @param levels 货架层数
     * @param itemsPerLevel 层货位数
     * @param startNumber 货位区开始编号
     * @param stoId 仓库id
     * @desc  地堆货位生成规则
     *
     */
    public List<String> generateDiDuiCodes(String prefix, int totalCount, String diDui,int levels, int itemsPerLevel, int startNumber,
                                      String stoId, String sonCode, String stoAreaId,String isSonShow) {
        // 创建一个 List 用来存储所有生成的编码
        List<String> codes = new ArrayList<>();
        //根据 ID 查询仓库信息
        Warehouse warehouse = warehouseMapper.selectWarehouseById(stoId);
        //查询货位表获取最大的排序作为货位区开始编号
        String stoCode;
        if (isSonShow.equals("1")) {
            stoCode = warehouse.getStoCode() + "-" + sonCode+"-" + prefix;
        } else {
            stoCode = warehouse.getStoCode() + "-" + sonCode + prefix;
        }
        //判断是否是地堆 新增地堆货架层数
        if (StringUtils.isNotBlank(diDui)) {
            stoCode += String.format("%2s", diDui).replace(' ', '0');
        }
        //模糊查询仓库下的这一类货位数据
        List<StoUnit> stoUnits = stoUnitMapper.selectStoCode(stoCode, stoId, stoAreaId);
        List<String> codeList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(stoUnits)) {
            String finalStoCode = stoCode;
            stoUnits.forEach(i -> {
                String replaceAll = i.getStoUnitCode().replaceAll(finalStoCode, "");
                codeList.add(replaceAll.substring(1, 3));
            });
        }
        int starNum = 1;
        if(CollectionUtil.isNotEmpty(codeList)){
            //去重排序
            List<String> collect = codeList.stream().distinct().collect(Collectors.toList());
            Collections.reverse(collect);
            //获取编码的开始位
            String value = collect.get(0);
            //根据value获取id
            starNum = warehouseMapper.selectDataDicListByUValue(value);
        }
        //查询库区位数据字典
        List<String> list = warehouseMapper.selectDataDicList(starNum+1, (totalCount + starNum));
        // 循环生成每个编码，从 startNumber 开始
        for (int i = 0; i < totalCount; i++) {
            String codePrefix;
            String format = list.get(i);
            if (StringUtils.isNotBlank(diDui)) {
                format = String.format("%2s", diDui).replace(' ', '0');
            }
            if (isSonShow.equals("1")) {
                codePrefix = String.format("%s-%s-%s%s", warehouse.getStoCode(), sonCode, prefix, format);
            } else {
                codePrefix = String.format("%s-%s%s", warehouse.getStoCode(), prefix, format);
            }
            for (int j = starNum; j < (starNum+levels); j++) {
                for (int k = 1; k <= itemsPerLevel; k++) {
                    String code = String.format("%s-%02d-%02d", codePrefix, j, k);
                    codes.add(code);
                }
            }
        }
        basicStoShelfMapper.updateBasicStoShelfByDef1((totalCount + startNumber) + "", prefix);
        return codes;
    }

    @Override
    public int updateStoUnit(StoUnit stoUnit)
    {
        return stoUnitMapper.updateStoUnit(stoUnit); // 更新货位
    }

    @Override
    public StoUnit getStoUnitById(String stoUnitId)
    {
        return stoUnitMapper.selectStoUnitById(stoUnitId); // 根据ID查询货位
    }

    @Override
    public List<StoUnit> getStoUnitsByAreaId(String stoAreaId)
    {
        return stoUnitMapper.selectStoUnitsByAreaId(stoAreaId); // 根据库区ID查询货位
    }

    @Override
    public List<StoUnit> getAllStoUnits(StoUnit stoUnit)
    {
        return stoUnitMapper.selectAllStoUnits(); // 查询所有货位
    }

    @Override
    public int deleteStoUnit(String stoUnitId)
    {
        return stoUnitMapper.deleteStoUnit(stoUnitId); // 删除货位
    }

    // 检查货位是否被使用
    public boolean isStoUnitInUse(String stoUnitId)
    {
        return stoUnitMapper.countUsageByStoUnitId(stoUnitId);
    }

    @Override
    public List<StoUnitVo> queryStoUnit(String stoAreaId)
    {
        List<StoUnit> list = stoUnitMapper.findStoUnitByStoAreaCodeAndStounitCode(stoAreaId);
        List<BasicStoShelf> basicStoShelves = basicStoShelfMapper.selectAllBasicStoShelf();
        Map<String, StoUnitVo> map = new HashMap<>();
        basicStoShelves.forEach(item -> {
            StoUnitVo vo = new StoUnitVo();
            vo.setShelfName(item.getName());
            vo.setTag(item.getTag());
            map.put(vo.getTag(), vo);
        });
        list.forEach(item -> {
            String tag = String.valueOf(item.getStoUnitCode().charAt(0));
            map.get(tag).getChildren().add(item);
        });

        List<StoUnitVo> vos = new ArrayList<>();
        map.forEach((k, v) -> {
            if(! v.getChildren().isEmpty()) {
                vos.add(v);
            }
        });

        return vos;
    }

    @Override
    public List<HashMap<String, Object>> queryStoUnit(String sto_area_code, String sto_unit_code)
    {
        return stoUnitMapper.queryStoUnit(sto_area_code, sto_unit_code);
    }


    @Override
    public List<HashMap<String, Object>> queryGoods(String name, String materialspec, String vbatchcode, String pkMaterial)
    {
        return stoUnitMapper.queryGoods(name, materialspec, vbatchcode, pkMaterial);
    }

    /**
     * 获取货位信息
     * @param stoAreaCode
     * @param stoUnitCode
     * @return
     */
    @Override
    public R queryStoUnitInfo(String stoAreaCode, String stoUnitCode)
    {
        List<HashMap<String, Object>> list = stoUnitMapper.queryStoUnitInfo(stoAreaCode, stoUnitCode);
        List<BasicStoShelf> basicStoShelves = basicStoShelfMapper.selectAllBasicStoShelf();
        Map<String, StoUnitVo> map = new HashMap<>();
        basicStoShelves.forEach(item -> {
            StoUnitVo vo = new StoUnitVo();
            vo.setShelfName(item.getName());
            vo.setTag(item.getTag());
            map.put(vo.getTag(), vo);
        });
        list.forEach(item -> {
            String unitCode = String.valueOf(item.get("sto_unit_code").toString());
            if (StringUtils.isNotBlank(unitCode)) {
                int length = unitCode.length();
                String substring = null;
                //KF-01-G01-01-06
                if (length == 15) {
                    substring = unitCode.substring(6,7);
                }
                //CP01-GF5-02-04
                if (length == 14) {
                    substring = unitCode.substring(5,6);
                }
                if (Objects.nonNull(substring)) {
                    if(Objects.nonNull(map.get(substring))){
                        map.get(substring).getChildren().add(item);
                    }
                }
            }
        });

        List<StoUnitVo> vos = new ArrayList<>();
        map.forEach((k, v) -> {
            if(! v.getChildren().isEmpty()) {
                vos.add(v);
            }
        });


        return R.ok(vos);
    }

    public String getThreeId()
    {
        Long aLong = stoUnitMapper.queryBigNumber();
        if(aLong == null) {
            return "3000000000";
        } else {
            aLong = aLong + 1;
            return aLong + "";
        }
    }

    @Override
    public R getAllStorageNumber(String stoId,String stoAreaId) {
        List<String> list = new ArrayList<>();
        //获取所有的货位编码
        List<StoUnit> stoUnits = stoUnitMapper.selectAllStoUnitCode(stoId,stoAreaId);
        if(CollectionUtil.isNotEmpty(stoUnits)){
            stoUnits.forEach(s->{
                String code = s.getStoUnitCode();
                if (StringUtils.isNotBlank(code)) {
                    //获取最后一个 - 的下标
                    int index = code.lastIndexOf("-");
                    //最后一个-的下标存在时进行截取
                    if (index != -1) {
                        list.add(code.substring(0, index));
                    }
                }
            });
            //数据非空时进行去重排序
            if(CollectionUtil.isNotEmpty(list)){
                List<String> collect = list.stream().distinct().sorted().collect(Collectors.toList());
                list.clear();
                list.addAll(collect);
            }
        }

        return R.ok(list);
    }
    @Override
    public AjaxResult addStoUnitStorage(StoUnit stoUnit) {
        // 获取登录用户信息
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser user = loginUser.getUser();

        String stoUnitCode = stoUnit.getStoUnitCode();
        List<StoUnit> existingUnits = stoUnitMapper.selectStoCode(stoUnitCode, stoUnit.getStoId(), stoUnit.getDosageId());

        // 获取已有最大序号（如果没有记录，从 0 开始）
        int maxIndex = existingUnits.stream()
                .map(StoUnit::getStoUnitCode)
                .filter(StringUtils::isNotEmpty)
                .map(code -> {
                    int idx = code.lastIndexOf("-");
                    return Integer.parseInt(idx != -1 ? code.substring(idx + 1) : code);
                })
                .max(Integer::compareTo)
                .orElse(0);

        // 查询货位分类标识（用于继承 gubflag）
        StoUnit unitGubFlag = stoUnitMapper.selectUnitGubFlag(stoUnitCode, stoUnit.getStoId());
        // 循环生成新货位编码
        for (int i = 1; i <= stoUnit.getNumber(); i++) {
            String newStoUnitCode = stoUnitCode + "-" + String.format("%02d", ++maxIndex);
            StoUnit newUnit = new StoUnit();
            BeanUtils.copyProperties(stoUnit, newUnit);
            // 初始化字段
            newUnit.setStoUnitCode(newStoUnitCode);
            newUnit.setCreator(user.getUserName());
            newUnit.setDef1("");
            newUnit.setDef2("");
            newUnit.setDef3("");
            newUnit.setDef4("");
            newUnit.setStoId(stoUnit.getStoId());
            newUnit.setStoAreaId(stoUnit.getStoAreaId());
            if (unitGubFlag != null && unitGubFlag.getGubflag() != null) {
                newUnit.setGubflag(unitGubFlag.getGubflag());
            }
            stoUnitMapper.insertStoUnit(newUnit);
        }
        return AjaxResult.success("操作成功");
    }


    @Override
    public R wmsReportUnitStatistic(String wareHouseID, String wareHouseValue, String wareHouseTypeID, String wareHouseTypeIDValue, String unitTypeId, String unitTypeIdValue, String sType) {
        //sType   统计类型：0：总体货位统计 1：仓储明细表 2：货位类型明细表 3：仓库类型明细表
        HashMap<String, Object> map = new HashMap<>();
        List<HashMap<String, Object>> list1 = stoUnitMapper.wmsReportUnitStatistic(wareHouseID, wareHouseValue, wareHouseTypeID, wareHouseTypeIDValue, unitTypeId, unitTypeIdValue, "0");
        List<HashMap<String, Object>> list2 = stoUnitMapper.wmsReportUnitStatistic(wareHouseID, wareHouseValue, wareHouseTypeID, wareHouseTypeIDValue, unitTypeId, unitTypeIdValue, "1");
        List<HashMap<String, Object>> list3 = stoUnitMapper.wmsReportUnitStatistic(wareHouseID, wareHouseValue, wareHouseTypeID, wareHouseTypeIDValue, unitTypeId, unitTypeIdValue, "2");
        List<HashMap<String, Object>> list4 = stoUnitMapper.wmsReportUnitStatistic(wareHouseID, wareHouseValue, wareHouseTypeID, wareHouseTypeIDValue, unitTypeId, unitTypeIdValue, "3");
//        //仓库类型数据格式转换
//        list4.parallelStream().forEach(item -> {
//            String picClassName = (String)item.get("pic_class_name");//仓库名称
//            String classNum = (String)item.get("ClassNum");//类型下总货位数量
//            String unitNum = (String)item.get("UnitNum");//货位数量
//            String name = (String)item.get("name");//货架类型
//            String allNum = (String)item.get("AllNum");//系统所有货位
//            String classPercent = (String)item.get("ClassPercent");//使用率
//            String unit_use = (String)item.get("unit_use");//使用还是未使用
//        });
        map.put("type1", list1);
        map.put("type2", list2);
        map.put("type3", list3);
        map.put("type4", list4);
        return R.ok(map);
    }

    @Override
    public R wmsReportBasicStatistic(String skuID, String skuclassId, String wareHouseID, String openBatchNo,
                                     String batchNo, String batchNoValue, String beginDate, String endDate,
                                     String turnoverRateMinVal, String turnoverRateMaxVal, String turnoverDay,
                                     String turnoverDayValue, String skuRateMinVal, String skuRateMaxVal,Integer pageNum,Integer pageSize) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportBasicStatistic(skuID, skuclassId, wareHouseID, openBatchNo, batchNo,
                batchNoValue, beginDate, endDate, turnoverRateMinVal, turnoverRateMaxVal, turnoverDay,
                turnoverDayValue, skuRateMinVal, skuRateMaxVal);
        return R.ok(DataProcessCommonUtils.getTableInfo(mapList, pageNum, pageSize));
    }
    private List<ExportReportBasicVo> convertBasicMapToVoList(Object rows) {
        if (rows == null) {
            return Collections.emptyList();
        }

        if (!(rows instanceof List<?>)) {
            return Collections.emptyList();
        }

        List<?> rowList = (List<?>) rows;
        List<ExportReportBasicVo> resultList = new ArrayList<>(rowList.size());

        for (Object item : rowList) {
            if (item instanceof Map<?, ?>) {
                Map<?, ?> rowMap = (Map<?, ?>) item;
                ExportReportBasicVo vo = new ExportReportBasicVo();
                vo.setSku_Code(getStringValue(rowMap, "Sku_Code"));
                vo.setGMP_Bar(getStringValue(rowMap, "GMP_Bar"));
                vo.setSenderCode(getStringValue(rowMap,"SenderCode"));
                vo.setSku_Name(getStringValue(rowMap, "Sku_Name"));
                vo.setMaterialspec(getStringValue(rowMap, "materialspec"));
                vo.setCunit_name(getStringValue(rowMap, "cunit_name"));
                vo.setBeginNum(rowMap.get("BeginNum").toString());
                vo.setDurInNum(rowMap.get("DurInNum").toString());
                vo.setEndNum(rowMap.get("EndNum").toString());
                vo.setAverageNum(rowMap.get("AverageNum").toString());
                vo.setDurOutNum(rowMap.get("DurOutNum").toString());
                vo.setDurReturnNum(rowMap.get("DurReturnNum").toString());
                vo.setRealOutNum(rowMap.get("RealOutNum").toString());
                vo.setVelocity(getStringValue(rowMap,"Velocity"));
                vo.setTurnaroundDays(String.valueOf(rowMap.get("TurnaroundDays")));
                vo.setUsageNum(getStringValue(rowMap,"UsageNum"));
                resultList.add(vo);
            }
        }
        return resultList;
    }
    @Override
    public AjaxResult exportReportBasicStatistic(String skuID, String skuclassId, String wareHouseID, String openBatchNo,
                                                 String batchNo, String batchNoValue, String beginDate, String endDate,
                                                 String turnoverRateMinVal, String turnoverRateMaxVal, String turnoverDay,
                                                 String turnoverDayValue, String skuRateMinVal, String skuRateMaxVal,Integer pageNum,Integer pageSize, HttpServletResponse response) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportBasicStatistic(skuID, skuclassId, wareHouseID, openBatchNo, batchNo,
                batchNoValue, beginDate, endDate, turnoverRateMinVal, turnoverRateMaxVal, turnoverDay,
                turnoverDayValue, skuRateMinVal, skuRateMaxVal);
        TableDataInfo tableInfo = DataProcessCommonUtils.getTableInfo(mapList, pageNum, pageSize);
        List<ExportReportBasicVo> list = convertBasicMapToVoList(tableInfo.getRows());
        ExcelUtil<ExportReportBasicVo> util = new ExcelUtil<>(ExportReportBasicVo.class);
        util.exportExcel(response, list, "基础报表", "基础报表", "基础报表");
        return AjaxResult.success();
    }

    @Override
    public AjaxResult exportPdfReportBasicStatistic(String skuID, String skuclassId, String wareHouseID, String openBatchNo, String batchNo, String batchNoValue, String beginDate, String endDate, String turnoverRateMinVal, String turnoverRateMaxVal, String turnoverDay, String turnoverDayValue, String skuRateMinVal, String skuRateMaxVal, Integer pageNum,Integer pageSize,HttpServletResponse response) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportBasicStatistic(skuID, skuclassId, wareHouseID, openBatchNo, batchNo,
                batchNoValue, beginDate, endDate, turnoverRateMinVal, turnoverRateMaxVal, turnoverDay,
                turnoverDayValue, skuRateMinVal, skuRateMaxVal);
        TableDataInfo tableInfo = DataProcessCommonUtils.getTableInfo(mapList, pageNum, pageSize);
        List<ExportReportBasicVo> list = convertBasicMapToVoList(tableInfo.getRows());
        ExcelPDFUtil<ExportReportBasicVo> pdfUtil = new ExcelPDFUtil<>(ExportReportBasicVo.class);
        return pdfUtil.exportPDF(response, list, "基础报表", "基础报表", getUsername(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()),"全量");
    }

    @Override
    public List<ExportReportBasicVo> exportCsvReportBasicStatistic(String skuID, String skuclassId, String wareHouseID, String openBatchNo, String batchNo, String batchNoValue, String beginDate, String endDate, String turnoverRateMinVal, String turnoverRateMaxVal, String turnoverDay, String turnoverDayValue, String skuRateMinVal, String skuRateMaxVal, Integer pageNum,Integer pageSize,HttpServletResponse response) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportBasicStatistic(skuID, skuclassId, wareHouseID, openBatchNo, batchNo,
                batchNoValue, beginDate, endDate, turnoverRateMinVal, turnoverRateMaxVal, turnoverDay,
                turnoverDayValue, skuRateMinVal, skuRateMaxVal);
        TableDataInfo tableInfo = DataProcessCommonUtils.getTableInfo(mapList, pageNum, pageSize);
        return convertBasicMapToVoList(tableInfo.getRows());
    }

    private List<ExportReportTurnoverVo> convertTurnoverMapToVoList(Object rows) {
        if (rows == null) {
            return Collections.emptyList();
        }

        if (!(rows instanceof List<?>)) {
            return Collections.emptyList();
        }

        List<?> rowList = (List<?>) rows;
        List<ExportReportTurnoverVo> resultList = new ArrayList<>(rowList.size());

        for (Object item : rowList) {
            if (item instanceof Map<?, ?>) {
                Map<?, ?> rowMap = (Map<?, ?>) item;
                ExportReportTurnoverVo vo = new ExportReportTurnoverVo();
                vo.setClassName(getStringValue(rowMap,"ClassName"));
                vo.setCwarehouse_name(getStringValue(rowMap,"cwarehouse_name"));
                vo.setSku_Code(getStringValue(rowMap, "Sku_Code"));
                vo.setGMP_Bar(getStringValue(rowMap, "GMP_Bar"));
                vo.setSenderCode(getStringValue(rowMap,"SenderCode"));
                vo.setSku_Name(getStringValue(rowMap, "Sku_Name"));
                vo.setMaterialspec(getStringValue(rowMap, "materialspec"));
                vo.setCunit_name(getStringValue(rowMap, "cunit_name"));
                vo.setVelocity(getStringValue(rowMap,"Velocity"));
                vo.setUsageNum(getStringValue(rowMap,"UsageNum"));
                resultList.add(vo);
            }
        }
        return resultList;
    }
    @Override
    public AjaxResult exportReportTurnoverStatistic(String skuID, String skuclassId, String wareHouseID, String openBatchNo, String batchNo, String batchNoValue, String beginDate, String endDate, String turnoverRateMinVal, String turnoverRateMaxVal, String turnoverDay, String turnoverDayValue, String skuRateMinVal, String skuRateMaxVal, Integer pageNum, Integer pageSize, HttpServletResponse response) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportBasicStatistic(skuID, skuclassId, wareHouseID, openBatchNo, batchNo,
                batchNoValue, beginDate, endDate, turnoverRateMinVal, turnoverRateMaxVal, turnoverDay,
                turnoverDayValue, skuRateMinVal, skuRateMaxVal);
        TableDataInfo tableInfo = DataProcessCommonUtils.getTableInfo(mapList, pageNum, pageSize);
        List<ExportReportTurnoverVo> list = convertTurnoverMapToVoList(tableInfo.getRows());
        ExcelUtil<ExportReportTurnoverVo> util = new ExcelUtil<>(ExportReportTurnoverVo.class);
        util.exportExcel(response, list, "周转率", "周转率", "周转率");
        return AjaxResult.success();
    }

    @Override
    public AjaxResult exportPdfReportTurnoverStatistic(String skuID, String skuclassId, String wareHouseID, String openBatchNo, String batchNo, String batchNoValue, String beginDate, String endDate, String turnoverRateMinVal, String turnoverRateMaxVal, String turnoverDay, String turnoverDayValue, String skuRateMinVal, String skuRateMaxVal, Integer pageNum, Integer pageSize, HttpServletResponse response) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportBasicStatistic(skuID, skuclassId, wareHouseID, openBatchNo, batchNo,
                batchNoValue, beginDate, endDate, turnoverRateMinVal, turnoverRateMaxVal, turnoverDay,
                turnoverDayValue, skuRateMinVal, skuRateMaxVal);
        TableDataInfo tableInfo = DataProcessCommonUtils.getTableInfo(mapList, pageNum, pageSize);
        List<ExportReportTurnoverVo> list = convertTurnoverMapToVoList(tableInfo.getRows());
        ExcelPDFUtil<ExportReportTurnoverVo> pdfUtil = new ExcelPDFUtil<>(ExportReportTurnoverVo.class);
        return pdfUtil.exportPDF(response, list, "周转率", "周转率", getUsername(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()),"全量");
    }

    @Override
    public List<ExportReportTurnoverVo> exportCsvReportTurnoverStatistic(String skuID, String skuclassId, String wareHouseID, String openBatchNo, String batchNo, String batchNoValue, String beginDate, String endDate, String turnoverRateMinVal, String turnoverRateMaxVal, String turnoverDay, String turnoverDayValue, String skuRateMinVal, String skuRateMaxVal, Integer pageNum, Integer pageSize, HttpServletResponse response) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportBasicStatistic(skuID, skuclassId, wareHouseID, openBatchNo, batchNo,
                batchNoValue, beginDate, endDate, turnoverRateMinVal, turnoverRateMaxVal, turnoverDay,
                turnoverDayValue, skuRateMinVal, skuRateMaxVal);
        TableDataInfo tableInfo = DataProcessCommonUtils.getTableInfo(mapList, pageNum, pageSize);
        return convertTurnoverMapToVoList(tableInfo.getRows());
    }

    @Override
    public R turnoverRate(String skuID, String skuclassId, String wareHouseID, String openBatchNo,
                          String batchNo, String batchNoValue, String beginDate, String endDate,
                          String turnoverRateMinVal, String turnoverRateMaxVal, String turnoverDay,
                          String turnoverDayValue, String skuRateMinVal, String skuRateMaxVal) {
        // 解析日期
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate localDate = LocalDate.parse(endDate, formatter); // 示例日期

        // 向前推3个月作为起始日期
        LocalDate startDate = localDate.minusMonths(3);

        // 调用存储过程获取初始数据（覆盖3个月范围）
        List<HashMap<String, Object>> newMapList = stoUnitMapper.wmsReportBasicStatistic(
                skuID, skuclassId, wareHouseID, openBatchNo, batchNo,
                batchNoValue, startDate.toString(), endDate.toString(),
                turnoverRateMinVal, turnoverRateMaxVal, turnoverDay,
                turnoverDayValue, skuRateMinVal, skuRateMaxVal
        );
        // 按pk_material分组并取每组Velocity前5的记录
        Map<String, List<Map<String, Object>>> result = newMapList.stream()
                .filter(m -> m.get("Velocity") != null)
                .collect(Collectors.groupingBy(
                        map -> String.valueOf(map.get("pk_material")),
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                list -> list.stream()
                                        .sorted(Comparator.comparing(
                                                m -> (BigDecimal) m.get("Velocity"),
                                                Comparator.reverseOrder()
                                        ))
                                        .limit(5)
                                        .collect(Collectors.toList())
                        )
                ));

        // 计算每个PK的Velocity总和，并找出总和最大的前5个PK
        List<String> top5Pks = result.entrySet().stream()
                .map(entry -> {
                    BigDecimal sum = entry.getValue().stream()
                            .map(m -> (BigDecimal) m.get("Velocity"))
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                    return new AbstractMap.SimpleEntry<>(entry.getKey(), sum);
                })
                .sorted(Map.Entry.<String, BigDecimal>comparingByValue(Comparator.reverseOrder()))
                .limit(5)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());

        // 计算3个月区间内的10个均匀分布的时间点
        long daysBetween = ChronoUnit.DAYS.between(startDate, localDate);
        long interval = daysBetween / 4; // 10个点需要9个间隔

        List<LocalDate> timePoints = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            timePoints.add(startDate.plusDays(i * interval));
        }

        // 为每个时间点生成top5商品的报表数据
        Map<LocalDate, List<HashMap<String, Object>>> reportResult = new LinkedHashMap<>();
        for (LocalDate timePoint : timePoints) {
            List<HashMap<String, Object>> timePointData = new ArrayList<>();

            // 为每个PK查询该时间点的数据
            for (String pk : top5Pks) {
                // 调用存储过程，传入单个时间点
                List<HashMap<String, Object>> pkData = stoUnitMapper.wmsReportBasicStatistic(
                        pk, skuclassId, wareHouseID, openBatchNo, batchNo,
                        batchNoValue, timePoint.toString(), timePoint.toString(),
                        turnoverRateMinVal, turnoverRateMaxVal, turnoverDay,
                        turnoverDayValue, skuRateMinVal, skuRateMaxVal
                );

                if (!pkData.isEmpty()) {
                    timePointData.add(pkData.get(0));
                }
            }
            // 按Velocity排序
            timePointData.sort(Comparator.comparing(
                    m -> (BigDecimal) m.get("Velocity"),
                    Comparator.reverseOrder()
            ));
            reportResult.put(timePoint, timePointData);
        }
        return R.ok(reportResult);
    }


    @Override
    public R wmsReportSluggishStatistic(String skuID, String skuClassID, String wareHouseID, String batchNo,
                                        String batchNoValue, String sluggishBegin, String sluggishEnd,Integer pageNum,Integer pageSize) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportSluggishStatistic(skuID, skuClassID, wareHouseID, batchNo, batchNoValue, sluggishBegin, sluggishEnd);
        double sum = 0;
        for (HashMap<String, Object> map : mapList) {
            Object inventoryNum = map.get("InventoryNum");
            if (inventoryNum instanceof Double) {
                sum += (Double) inventoryNum;
            } else if (inventoryNum instanceof String) {
                try {
                    sum += Double.parseDouble((String) inventoryNum);
                } catch (NumberFormatException e) {
                    // 处理非数字字符串的情况，这里选择忽略
                }
            }
        }
        return R.ok(DataProcessCommonUtils.getTableInfo(mapList,sum, (double) 0, pageNum, pageSize));
    }

    @Override
    public AjaxResult exportReportSluggishStatistic(String skuID, String skuClassID, String wareHouseID, String batchNo, String batchNoValue, String sluggishBegin, String sluggishEnd, Integer pageNum, Integer pageSize, HttpServletResponse response) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportSluggishStatistic(skuID, skuClassID, wareHouseID, batchNo, batchNoValue, sluggishBegin, sluggishEnd);
        // 分页处理
        TableDataInfo tableInfo = DataProcessCommonUtils.getTableInfo(mapList, pageNum, pageSize);

        // 安全地将Map转换为VO对象
        List<ExportReportSluggishVo> exportList = convertSluggishMapToVoList(tableInfo.getRows());

        // 导出Excel
        ExcelUtil<ExportReportSluggishVo> util = new ExcelUtil<>(ExportReportSluggishVo.class);
        util.exportExcel(response, exportList, "呆滞物料", "呆滞物料", "呆滞物料");

        return AjaxResult.success(exportList);
    }

    /**
     * 安全地将Map列表转换为ExportReportSluggishVo列表，包含完整的空值处理
     */
    private List<ExportReportSluggishVo> convertSluggishMapToVoList(Object rows) {
        if (rows == null) {
            return Collections.emptyList();
        }

        if (!(rows instanceof List<?>)) {
            return Collections.emptyList();
        }

        List<?> rowList = (List<?>) rows;
        List<ExportReportSluggishVo> resultList = new ArrayList<>(rowList.size());

        for (Object item : rowList) {
            if (item instanceof Map<?, ?>) {
                Map<?, ?> rowMap = (Map<?, ?>) item;
                ExportReportSluggishVo vo = new ExportReportSluggishVo();

                // 使用泛型方法进行安全的类型转换和空值处理
                vo.setVsender_name(getStringValue(rowMap, "vsender_name"));
                vo.setClassName(getStringValue(rowMap, "ClassName"));
                vo.setSku_Code(getStringValue(rowMap, "Sku_Code"));
                vo.setGMP_Bar(getStringValue(rowMap, "GMP_Bar"));
                vo.setSenderCode(getStringValue(rowMap, "SenderCode"));
                vo.setSku_Name(getStringValue(rowMap, "Sku_Name"));
                vo.setMaterialspec(getStringValue(rowMap, "materialspec"));
                vo.setCunit_name(getStringValue(rowMap, "cunit_name"));
                vo.setVbatchcode(getStringValue(rowMap, "vbatchcode"));

                // 数值类型的安全转换
                vo.setInventoryNum(getStringValue(rowMap, "InventoryNum"));
                vo.setSluggishDay(getStringValue(rowMap, "SluggishDay"));

                // 日期类型的安全转换
                vo.setOperatTime(formatDate(rowMap.get("operatTime")));

                // 仓库名称
                vo.setCwarehouse_name(getStringValue(rowMap, "cwarehouse_name"));

                resultList.add(vo);
            }
        }

        return resultList;
    }

    /**
     * 从Map中获取字符串值，并进行空值处理
     */
    private String getStringValue(Map<?, ?> map, String key) {
        Object value = map.get(key);
        if (value == null) {
            return "";
        }
        return String.valueOf(value);
    }

    /**
     * 安全地格式化日期
     */
    private String formatDate(Object dateObj) {
        if (dateObj == null) {
            return "";
        }
        if (dateObj instanceof Date) {
            return DateUtils.parseDateToStr("yyyy-MM-dd", (Date) dateObj);
        }
        // 处理可能的时间戳或其他格式
        try {
            if (dateObj instanceof Number) {
                Date date = new Date(((Number) dateObj).longValue());
                return DateUtils.parseDateToStr("yyyy-MM-dd", date);
            }
            // 尝试解析字符串日期
            if (dateObj instanceof String) {
                Date date = DateUtils.parseDate(dateObj.toString());
                return DateUtils.parseDateToStr("yyyy-MM-dd", date);
            }
        } catch (Exception e) {
            log.warn("日期解析失败: {}", e.getMessage());
        }
        return "";
    }

    @Override
    public R wmsReportUnqualifiedStatistic(String skuClassId, String skuID, String batchNo, String batchNoValue, Integer pageNum, Integer pageSize) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportUnqualifiedStatistic(skuClassId, skuID, batchNo, batchNoValue);
        double sum = 0;
        double sum1 = 0;
        for (HashMap<String, Object> map : mapList) {
            Object inventoryNum = map.get("unqualified_num");
            Object unTotalQuantity = map.get("un_total_quantity");
            if (inventoryNum instanceof Double) {
                sum += (Double) inventoryNum;
            } else if (inventoryNum instanceof String) {
                try {
                    sum += Double.parseDouble((String) inventoryNum);
                } catch (NumberFormatException e) {
                    // 处理非数字字符串的情况，这里选择忽略
                }
            }
            if (unTotalQuantity instanceof Double) {
                sum1 += (Double) unTotalQuantity;
            } else if (unTotalQuantity instanceof String) {
                try {
                    sum1 += Double.parseDouble((String) unTotalQuantity);
                } catch (NumberFormatException e) {
                    // 处理非数字字符串的情况，这里选择忽略
                }
            }
        }
        return R.ok(DataProcessCommonUtils.getTableInfo(mapList, sum,sum1, pageNum, pageSize));
    }

    @Override
    public AjaxResult exportReportUnqualifiedStatistic(String skuClassId, String skuID, String batchNo, String batchNoValue,Integer pageNum,Integer pageSize, HttpServletResponse response) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportUnqualifiedStatistic(skuClassId, skuID, batchNo, batchNoValue);
        // 分页处理
        TableDataInfo tableInfo = DataProcessCommonUtils.getTableInfo(mapList, pageNum, pageSize);

        // 安全地将Map转换为VO对象
        List<ExportReportUnqualifiedVo> exportList = convertUnqualifiedMapToVoList(tableInfo.getRows());

        // 导出Excel
        ExcelUtil<ExportReportUnqualifiedVo> util = new ExcelUtil<>(ExportReportUnqualifiedVo.class);
        util.exportExcel(response, exportList, "不合格品台账", "不合格品台账", "不合格品台账");

        return AjaxResult.success(exportList);
    }

    /**
     * 安全地将Map列表转换为ExportSkuAlarmsVo列表
     * @param rows 原始数据行
     * @return 转换后的VO列表
     */
    private List<ExportReportUnqualifiedVo> convertUnqualifiedMapToVoList(Object rows) {
        if (rows == null) {
            return Collections.emptyList();
        }

        if (!(rows instanceof List<?>)) {
            return Collections.emptyList();
        }

        List<?> rowList = (List<?>) rows;
        List<ExportReportUnqualifiedVo> resultList = new ArrayList<>(rowList.size());

        for (Object item : rowList) {
            if (item instanceof Map<?, ?>) {
                Map<?, ?> rowMap = (Map<?, ?>) item;
                ExportReportUnqualifiedVo vo = new ExportReportUnqualifiedVo();
//                vo.setOperatTime(formatDate(rowMap.get("operatTime")));
                vo.setClassName(getStringValue(rowMap, "ClassName"));
                vo.setSku_Code(getStringValue(rowMap, "Sku_Code"));
                vo.setGMP_Bar(getStringValue(rowMap, "GMP_Bar"));
                vo.setSenderCode(getStringValue(rowMap, "SenderCode"));
                vo.setSto_unit_id(getStringValue(rowMap, "sto_unit_id"));
                vo.setSku_Name(getStringValue(rowMap, "Sku_Name"));
                vo.setMaterialspec(getStringValue(rowMap, "materialspec"));
                vo.setVbatchcode(getStringValue(rowMap, "vbatchcode"));
                vo.setCunit_name(getStringValue(rowMap, "cunit_name"));
//                vo.setUnit_name(getStringValue(rowMap, "cunit_name"));
                vo.setUnqualified_num(rowMap.get("unqualified_num").toString());
                vo.setInventoryNum(rowMap.get("InventoryNum").toString());
                vo.setOperator(getStringValue(rowMap, "operator"));
                resultList.add(vo);
            }
        }

        return resultList;
    }

    @Override
    public AjaxResult exportPdfReportUnqualifiedStatistic(String skuClassId, String skuID, String batchNo, String batchNoValue,Integer pageNum,Integer pageSize, HttpServletResponse response) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportUnqualifiedStatistic(skuClassId, skuID, batchNo, batchNoValue);
        // 分页处理
        TableDataInfo tableInfo = DataProcessCommonUtils.getTableInfo(mapList, pageNum, pageSize);

        // 安全地将Map转换为VO对象
        List<ExportReportUnqualifiedVo> exportList = convertUnqualifiedMapToVoList(tableInfo.getRows());
        ExcelPDFUtil<ExportReportUnqualifiedVo> pdfUtil = new ExcelPDFUtil<>(ExportReportUnqualifiedVo.class);
        return pdfUtil.exportPDF(response, exportList, "不合格品台账", "不合格品台账", getUsername(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()),"全量");
    }

    @Override
    public List<ExportReportUnqualifiedVo> exportCsvReportUnqualifiedStatistic(String skuClassId, String skuID, String batchNo, String batchNoValue, Integer pageNum, Integer pageSize, HttpServletResponse response) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportUnqualifiedStatistic(skuClassId, skuID, batchNo, batchNoValue);
        // 分页处理
        TableDataInfo tableInfo = DataProcessCommonUtils.getTableInfo(mapList, pageNum, pageSize);
        // 安全地将Map转换为VO对象
        return convertUnqualifiedMapToVoList(tableInfo.getRows());
    }

    @Override
    public R wmsReportDeliveryStatistic(String skuID, String wareHouseID, String shippingMethod, String customerID,
                                        String vbillsCode, String batchNo, String batchNoValue, String wareHouseOutBills,
                                        String beginDate, String endDate,Integer pageNum,Integer pageSize) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportDeliveryStatistic(skuID, wareHouseID, shippingMethod, customerID,
                vbillsCode, batchNo, batchNoValue, wareHouseOutBills, beginDate, endDate);
        return R.ok(DataProcessCommonUtils.getTableInfo(mapList, pageNum, pageSize));
    }

    /**
     * 安全地将Map列表转换为ExportSkuAlarmsVo列表
     * @param rows 原始数据行
     * @return 转换后的VO列表
     */
    private List<ExportReportDeliveryVo> convertDeliveryMapToVoList(Object rows) {
        if (rows == null) {
            return Collections.emptyList();
        }

        if (!(rows instanceof List<?>)) {
            return Collections.emptyList();
        }

        List<?> rowList = (List<?>) rows;
        List<ExportReportDeliveryVo> resultList = new ArrayList<>(rowList.size());

        for (Object item : rowList) {
            if (item instanceof Map<?, ?>) {
                Map<?, ?> rowMap = (Map<?, ?>) item;
                ExportReportDeliveryVo vo = new ExportReportDeliveryVo();
                vo.setDmakedate(formatDate(rowMap.get("dmakedate")));
                vo.setCmaterialoid_code(getStringValue(rowMap, "cmaterialoid_code"));
                vo.setGraphid(getStringValue(rowMap, "graphid"));
                vo.setVbcdef2(getStringValue(rowMap, "vbcdef2"));
                vo.setCmaterialoid_name(getStringValue(rowMap, "cmaterialoid_name"));
                vo.setMaterialtype(getStringValue(rowMap, "materialtype"));
                vo.setVbatchcode(getStringValue(rowMap, "vbatchcode"));
                vo.setNnum(rowMap.get("nnum").toString());
                vo.setCunitid_name(getStringValue(rowMap, "cunitid_name"));
                vo.setNassistnum(rowMap.get("nassistnum").toString());
                vo.setCastunitid_name(getStringValue(rowMap, "castunitid_name"));
                vo.setCcustomerid_name(getStringValue(rowMap, "ccustomerid_name"));
                vo.setVdef21(getStringValue(rowMap, "vdef21"));
                vo.setVdef10(getStringValue(rowMap, "vdef10"));
                vo.setVdef7(getStringValue(rowMap, "vdef7"));
                vo.setVdef8(getStringValue(rowMap, "vdef8"));
                vo.setVdef47_name(getStringValue(rowMap, "vdef47_name"));
                vo.setVdef26(getStringValue(rowMap, "vdef26"));
                vo.setVbillcode(getStringValue(rowMap, "vbillcode"));
                vo.setCwarehouseid_name(getStringValue(rowMap, "cwarehouseid_name"));
                resultList.add(vo);
            }
        }

        return resultList;
    }
    @Override
    public AjaxResult exportReportDeliveryStatistic(String skuID, String wareHouseID, String shippingMethod, String customerID,
                                                    String vbillsCode, String batchNo, String batchNoValue, String wareHouseOutBills, String beginDate, String endDate, Integer pageNum,Integer pageSize,HttpServletResponse response) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportDeliveryStatistic(skuID, wareHouseID, shippingMethod, customerID,
                vbillsCode, batchNo, batchNoValue, wareHouseOutBills, beginDate, endDate);
        // 分页处理
        TableDataInfo tableInfo = DataProcessCommonUtils.getTableInfo(mapList, pageNum, pageSize);

        // 安全地将Map转换为VO对象
        List<ExportReportDeliveryVo> exportList = convertDeliveryMapToVoList(tableInfo.getRows());

        // 导出Excel
        ExcelUtil<ExportReportDeliveryVo> util = new ExcelUtil<>(ExportReportDeliveryVo.class);
        util.exportExcel(response, exportList, "产品发运记录", "产品发运记录", "产品发运记录");

        return AjaxResult.success();
    }

    @Override
    public AjaxResult exportPdfReportDeliveryStatistic(String skuID, String wareHouseID, String shippingMethod, String customerID,
                                                       String vbillsCode, String batchNo, String batchNoValue, String wareHouseOutBills, String beginDate, String endDate,Integer pageNum,Integer pageSize, HttpServletResponse response) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportDeliveryStatistic(skuID, wareHouseID, shippingMethod, customerID,
                vbillsCode, batchNo, batchNoValue, wareHouseOutBills, beginDate, endDate);
        // 分页处理
        TableDataInfo tableInfo = DataProcessCommonUtils.getTableInfo(mapList, pageNum, pageSize);

        // 安全地将Map转换为VO对象
        List<ExportReportDeliveryVo> exportList = convertDeliveryMapToVoList(tableInfo.getRows());
        ExcelPDFUtil<ExportReportDeliveryVo> pdfUtil = new ExcelPDFUtil<>(ExportReportDeliveryVo.class);
        return pdfUtil.exportPDF(response, exportList, "产品发运记录", "产品发运记录", getUsername(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()),"全量");
    }

    @Override
    public List<ExportReportDeliveryVo> exportCsvReportDeliveryStatistic(String skuID, String wareHouseID, String shippingMethod,
                                                                          String customerID, String vbillsCode, String batchNo, String batchNoValue, String wareHouseOutBills, String beginDate, String endDate,Integer pageNum,Integer pageSize, HttpServletResponse response) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportDeliveryStatistic(skuID, wareHouseID, shippingMethod, customerID,
                vbillsCode, batchNo, batchNoValue, wareHouseOutBills, beginDate, endDate);
        // 分页处理
        TableDataInfo tableInfo = DataProcessCommonUtils.getTableInfo(mapList, pageNum, pageSize);

        // 安全地将Map转换为VO对象
        return convertDeliveryMapToVoList(tableInfo.getRows());
    }

    @Override
    public R wmsReportReceivingStatistic(String skuClassId, String receivingDay, String releaseDay, String stateID, String skuID, String senderID,
                                         String manufacturerID, String batchNo, String batchNoValue, Integer pageNum, Integer pageSize) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportReceivingStatistic(skuClassId, receivingDay, releaseDay, stateID, skuID, senderID, manufacturerID, batchNo, batchNoValue);
        double sum = 0;
        for (HashMap<String, Object> map : mapList) {
            Object inventoryNum = map.get("sku_num");
            if (inventoryNum instanceof Double) {
                sum += (Double) inventoryNum;
            } else if (inventoryNum instanceof String) {
                try {
                    sum += Double.parseDouble((String) inventoryNum);
                } catch (NumberFormatException e) {
                    // 处理非数字字符串的情况，这里选择忽略

                }
            }
        }
        return R.ok(DataProcessCommonUtils.getTableInfo(mapList, sum, (double) 0, pageNum, pageSize));
    }

    private List<ExportReportReceivingVo> convertReceivingMapToVoList(Object rows) {
        if (rows == null) {
            return Collections.emptyList();
        }

        if (!(rows instanceof List<?>)) {
            return Collections.emptyList();
        }

        List<?> rowList = (List<?>) rows;
        List<ExportReportReceivingVo> resultList = new ArrayList<>(rowList.size());

        for (Object item : rowList) {
            if (item instanceof Map<?, ?>) {
                Map<?, ?> rowMap = (Map<?, ?>) item;
                ExportReportReceivingVo vo = new ExportReportReceivingVo();
                vo.setOperatTime(formatDate(rowMap.get("operatTime")));
                vo.setSku_Code(getStringValue(rowMap, "Sku_Code"));
                vo.setGMP_Bar(getStringValue(rowMap, "GMP_Bar"));
                vo.setSenderCode(getStringValue(rowMap, "SenderCode"));
                vo.setSku_Name(getStringValue(rowMap, "Sku_Name"));
                vo.setClassName(getStringValue(rowMap, "ClassName"));
                vo.setMaterialspec(getStringValue(rowMap, "materialspec"));
                vo.setCunit_name(getStringValue(rowMap, "cunit_name"));
                vo.setSku_num(rowMap.get("sku_num").toString());
                vo.setVvendbatchcode(getStringValue(rowMap, "vvendbatchcode"));
                vo.setVbatchcode(getStringValue(rowMap, "vbatchcode"));
                vo.setCproduct_name(getStringValue(rowMap, "cproduct_name"));
                vo.setVsender_name(getStringValue(rowMap, "vsender_name"));
                vo.setPd_date(formatDate(rowMap.get("pd_date")));
                vo.setExp_date(formatDate(rowMap.get("exp_date")));
                vo.setRetest_date(formatDate(rowMap.get("retest_date")));
                vo.setInspection_date(formatDate(rowMap.get("inspection_date")));
                vo.setOperator(getStringValue(rowMap,"operator"));
                vo.setInspection_state(getStringValue(rowMap,"inspection_state"));
                vo.setPass_date(formatDate(rowMap.get("pass_date")));
                resultList.add(vo);
            }
        }
        return resultList;
    }
    @Override
    public AjaxResult exportReportReceivingStatistic(String skuClassId,String receivingDay, String releaseDay, String stateID, String skuID, String senderID,
                                                     String manufacturerID, String batchNo, String batchNoValue, Integer pageNum,Integer pageSize,HttpServletResponse response) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportReceivingStatistic(skuClassId, receivingDay, releaseDay, stateID, skuID, senderID, manufacturerID, batchNo, batchNoValue);
        TableDataInfo tableInfo = DataProcessCommonUtils.getTableInfo(mapList, pageNum, pageSize);
        List<ExportReportReceivingVo> list = convertReceivingMapToVoList(tableInfo.getRows());
        ExcelUtil<ExportReportReceivingVo> util = new ExcelUtil<>(ExportReportReceivingVo.class);
        util.exportExcel(response, list, "入厂总账", "入厂总账", "入厂总账");
        return AjaxResult.success();
    }

    @Override
    public AjaxResult exportPdfReportReceivingStatistic(String skuClassId,String receivingDay, String releaseDay, String stateID, String skuID, String senderID,
                                                        String manufacturerID, String batchNo, String batchNoValue, Integer pageNum,Integer pageSize,HttpServletResponse response) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportReceivingStatistic(skuClassId, receivingDay, releaseDay, stateID, skuID, senderID, manufacturerID, batchNo, batchNoValue);
        TableDataInfo tableInfo = DataProcessCommonUtils.getTableInfo(mapList, pageNum, pageSize);
        List<ExportReportReceivingVo> list = convertReceivingMapToVoList(tableInfo.getRows());
        ExcelPDFUtil<ExportReportReceivingVo> pdfUtil = new ExcelPDFUtil<>(ExportReportReceivingVo.class);
        return pdfUtil.exportPDF(response, list, "入厂总账", "入厂总账", getUsername(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()),"全量");
    }

    @Override
    public List<ExportReportReceivingVo> exportCsvReportReceivingStatistic(String skuClassId, String receivingDay, String releaseDay, String stateID, String skuID, String senderID,
                                                                           String manufacturerID, String batchNo, String batchNoValue, Integer pageNum, Integer pageSize, HttpServletResponse response) {
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsReportReceivingStatistic(skuClassId, receivingDay, releaseDay, stateID, skuID, senderID, manufacturerID, batchNo, batchNoValue);
        TableDataInfo tableInfo = DataProcessCommonUtils.getTableInfo(mapList, pageNum, pageSize);
        return convertReceivingMapToVoList(tableInfo.getRows());
    }

    public R wmsOnYearAndChainReport(String skuID, String skuclassId, String wareHouseID, String openBatchNo,
                                     String batchNo, String batchNoValue, String beginDate, String endDate,
                                     String turnoverRateMinVal, String turnoverRateMaxVal, String turnoverDay,
                                     String turnoverDayValue, String skuRateMinVal, String skuRateMaxVal, String beginDate1, String endDate1) {
        List<HashMap<String, Object>> resultList = new ArrayList<>();
        // 1. 获取原始数据
        List<HashMap<String, Object>> currentData = stoUnitMapper.wmsReportBasicStatistic(
                skuID, skuclassId, wareHouseID, openBatchNo, batchNo,
                batchNoValue, beginDate, endDate, turnoverRateMinVal,
                turnoverRateMaxVal, turnoverDay, turnoverDayValue,
                skuRateMinVal, skuRateMaxVal
        );
        // 1. 获取原始数据
        List<HashMap<String, Object>> yearOnYear = stoUnitMapper.wmsReportBasicStatistic(
                skuID, skuclassId, wareHouseID, openBatchNo, batchNo,
                batchNoValue, beginDate1, endDate1, turnoverRateMinVal,
                turnoverRateMaxVal, turnoverDay, turnoverDayValue,
                skuRateMinVal, skuRateMaxVal
        );
        resultList.addAll(currentData);
        resultList.addAll(yearOnYear);
        // 4. 构建返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("current", resultList);
        return R.ok(result);
    }

    // 计算同比（去年同期数据）
    private List<HashMap<String, Object>> calculateYearOnYear(String skuID, String skuclassId, String wareHouseID,
                                                    String openBatchNo, String batchNo, String batchNoValue, String beginDate, String endDate,
                                                    String turnoverRateMinVal, String turnoverRateMaxVal, String turnoverDay, String turnoverDayValue,
                                                    String skuRateMinVal, String skuRateMaxVal) {

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate currentStart = LocalDate.parse(beginDate, formatter);
        LocalDate currentEnd = LocalDate.parse(endDate, formatter);

        // 计算去年同期日期范围（前推1年）
        LocalDate lastYearStart = currentStart.minusYears(1);
        LocalDate lastYearEnd = currentEnd.minusYears(1);

        // 获取去年同期数据
        List<HashMap<String, Object>> result = stoUnitMapper.wmsReportBasicStatistic(
                skuID, skuclassId, wareHouseID, openBatchNo, batchNo,
                batchNoValue, lastYearStart.toString(), lastYearEnd.toString(),
                turnoverRateMinVal, turnoverRateMaxVal, turnoverDay,
                turnoverDayValue, skuRateMinVal, skuRateMaxVal
        );
        return result;
    }

    // 计算环比（上个月/上个周期数据）
    private List<HashMap<String, Object>> calculateMonthOnMonth(String skuID, String skuclassId, String wareHouseID,
                                                                String openBatchNo, String batchNo, String batchNoValue, String beginDate, String endDate,
                                                                String turnoverRateMinVal, String turnoverRateMaxVal, String turnoverDay, String turnoverDayValue,
                                                                String skuRateMinVal, String skuRateMaxVal) {

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate currentStart = LocalDate.parse(beginDate, formatter);
        LocalDate currentEnd = LocalDate.parse(endDate, formatter);

        // 计算环比日期范围（前推1个月或1个周期）
        long daysBetween = ChronoUnit.DAYS.between(currentStart, currentEnd);
        LocalDate lastPeriodStart = currentStart.minusDays(daysBetween + 1);
        LocalDate lastPeriodEnd = currentStart.minusDays(1);

        // 获取环比数据
        List<HashMap<String, Object>> result = stoUnitMapper.wmsReportBasicStatistic(
                skuID, skuclassId, wareHouseID, openBatchNo, batchNo,
                batchNoValue, lastPeriodStart.toString(), lastPeriodEnd.toString(),
                turnoverRateMinVal, turnoverRateMaxVal, turnoverDay,
                turnoverDayValue, skuRateMinVal, skuRateMaxVal
        );
        return result;
    }

    @Override
    public R wmsInventoryCountReport(String inventoryID, String warehouseId,Integer pageNum,Integer pageSize) {
        HashMap<String,Object> resultMap = new HashMap<>();
        List<HashMap<String, Object>> mapList = stoUnitMapper.wmsInventoryCountReport(inventoryID, warehouseId);
        List<HashMap<String, Object>> noCountReport = stoUnitMapper.wmsNoCountReport(inventoryID, warehouseId);
        resultMap.put("countData",DataProcessCommonUtils.getTableInfo(mapList, pageNum, pageSize));
        resultMap.put("noCountData",DataProcessCommonUtils.getTableInfo(noCountReport, pageNum, pageSize));
        return R.ok(resultMap);
    }
}
